#include <REGX52.H>
#include <INTRINS.H>

//引脚定义
sbit LCD_RW = P2^5;		//读写标志位，0为写
sbit LCD_RS = P2^6;		//数据/指令选择，0为指令
sbit LCD_EN = P2^7;		//使能，1为数据有效，下降沿执行命令

#define LCD_DATAPORT P0

/**
  * @brief		延迟1ms
  * @parm		无
  * @retval		无
  */
void LCD_Delay1ms()		//@11.0592MHz
{
	unsigned char i, j;

	_nop_();
	i = 2;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
}

/**
  * @brief		写命令
  * @parm		Command:命令
  * @retval		无
  */
void LCD_WriteCommand(unsigned char Command)
{
	LCD_RS = 0;					//命令
	LCD_RW = 0;					//写
	LCD_DATAPORT = Command;		//写命令
	LCD_EN = 1;					//拉高使能
	LCD_Delay1ms();
	LCD_EN = 0;					//拉低使能
	LCD_Delay1ms();
}

/**
  * @brief		写数据
  * @parm		Data:数据
  * @retval		无
  */
void LCD_WriteData(unsigned char Data)
{
	LCD_RS = 1;					//命令
	LCD_RW = 0;					//写
	LCD_DATAPORT = Data;		//写命令
	LCD_EN = 1;					//拉高使能
	LCD_Delay1ms();
	LCD_EN = 0;					//拉低使能
	LCD_Delay1ms();
}

/**
  * @brief		初始化LCD1602
  * @parm		无
  * @retval		无
  */
void LCD_Init()
{
	LCD_WriteCommand(0x38);		//八位数据接口，两行显示，5*7点阵
	//LCD_WriteCommand(0x0F);		//显示开，光标开，闪烁开
	LCD_WriteCommand(0x0C);		//显示开，光标关，闪烁关
	LCD_WriteCommand(0x06);		//数据读写操作后，光标自动加一，画面不动
	LCD_WriteCommand(0x01);		//清屏
}

/**
  * @brief		设置光标位置
  * @parm		Row:行号，范围：1 ~ 2
  * @parm		Column:列号，范围：1 ~ 40
  * @retval		无
  */
void LCD_SetCursor(unsigned char Row, unsigned char Column)
{
	if(Row == 1)	//第一行起始为0x00
		LCD_WriteCommand(0x80 | (Column - 1));
	else			//第二行起始为0x40
		LCD_WriteCommand(0x80 | (Column - 1) + 0x40);
}

/**
  * @brief		显示一个字符
  * @parm		Row:行号，范围：1 ~ 2
  * @parm		Column:列号，范围：1 ~ 40
  * @parm		Char:字符
  * @retval		无
  */
void LCD_ShowChar(unsigned char Row, Column, Char)
{
	LCD_SetCursor(Row, Column);
	LCD_WriteData(Char);
}

/**
  * @brief		显示一个字符
  * @parm		Row:行号，范围：1 ~ 2
  * @parm		Column:列号，范围：1 ~ 40
  * @parm		String:字符串
  * @retval		无
  */
void LCD_ShowString(unsigned char Row, unsigned char Column, unsigned char *String)
{
	unsigned char i = 0;
	LCD_SetCursor(Row, Column);
	for(i = 0; String[i] != '\0'; ++i)
		LCD_WriteData(String[i]);
}

/**
  * @brief		X的Y次方
  * @parm		X：基数
  * @parm		Y：次方数
  * @retval		X^Y
  */
unsigned long LCD_Pow(int X, int Y)
{
	unsigned long res = 1;
	while(Y--)
	{
		res *= X;
	}
	return res;
}

/**
  * @brief		在指定位置显示指定长度的无符号数字，从高位截取
  * @parm		Row: 行号，范围：1/2
  * @parm		Column: 列号，范围：1 ~ 40
  * @parm		Num: 显示的数字，范围：0 ~ 65535
  * @parm		Length: 长度，范围：1 ~ 40
  * @retval		无
  */
void LCD_ShowNum(unsigned char Row, unsigned char Column, unsigned int Num, unsigned char Length)
{
	LCD_SetCursor(Row, Column);
	for(; Length > 0; --Length)
		LCD_WriteData((Num / LCD_Pow(10, Length - 1) % 10) + '0');
}

/**
  * @brief		在指定位置显示指定长度的有符号数字，从高位截取
  * @parm		Row: 行号，范围：1/2
  * @parm		Column: 列号，范围：1 ~ 40
  * @parm		Num: 显示的数字，范围：-32768 ~ 32767。
  * @parm		Length: 长度，范围：1 ~ 40
  * @retval		无
  */
void LCD_ShowSignedNum(unsigned char Row, unsigned char Column, int Num, unsigned char Length)
{
	//显示正负号
	unsigned int ShowNum;
	if(Num >= 0){
		LCD_ShowChar(Row, Column, '+');
		ShowNum = Num;
	}	
	else{
		LCD_ShowChar(Row, Column, '-');
		ShowNum = -Num;
	}
	LCD_ShowNum(Row, Column + 1, ShowNum, Length);
}

/**
  * @brief		在指定位置显示指定长度的十六进制数字
  * @parm		Row: 行号，范围：1/2
  * @parm		Column: 列号，范围：1 ~ 40
  * @parm		Num: 显示的数字，范围：0 ~ 65535
  * @parm		Length: 长度，范围：1 ~ 40
  * @retval		无
  */
void LCD_ShowHexNum(unsigned char Row, unsigned char Column, unsigned int Num, unsigned char Length)
{
	unsigned char Temp;
	LCD_SetCursor(Row, Column);
	for(; Length > 0; --Length)
	{
		Temp = Num / LCD_Pow(16, Length - 1) % 16;
		if(Temp >= 10)
			LCD_WriteData(Temp - 10 + 'A');
		else
			LCD_WriteData(Temp + '0');
	}
}

/**
  * @brief		在指定位置显示指定长度的二进制数字
  * @parm		Row: 行号，范围：1/2
  * @parm		Column: 列号，范围：1 ~ 40
  * @parm		Num: 显示的数字，范围：0 ~ 65535
  * @parm		Length: 长度，范围：1 ~ 40
  * @retval		无
  */
void LCD_ShowBinNum(unsigned char Row, unsigned char Column, unsigned int Num, unsigned char Length)
{
	LCD_SetCursor(Row, Column);
	for(; Length > 0; --Length)
		LCD_WriteData(Num / LCD_Pow(2, Length - 1) % 2 + '0');
}







